package com.jdk.learn.nio._02;


import org.apache.commons.lang.StringUtils;
import org.junit.Test;

import java.nio.ByteBuffer;

/**
 * Created by ricky
 * on 2018/2/6.
 *
 缓冲区(buffer):
        NIO中负责数据的存取。缓冲区就是数组。用于存储不同类型的数据。

 相应的缓冲区(没有boolean)
    ByteBuffer
    CharBuffer
    ShortBuffer
    IntBuffer
    LongBuffer
    FloatBuffer
    DoubleBuffer

    以上缓冲区分配方式基本一致，即通过allocate()进行分配

 缓冲区中存取数据的方法：
    put():存入数据到缓冲区
    get():获取缓冲区的数据

 缓冲区中的四个核心属性
     // Invariants: mark <= position <= limit <= capacity
     private int mark = -1;   // 标记当前position的位置  通过reset()方法可以返回到mark的位置。
     private int position = 0;// 标示缓冲区中正在操作的数据的位置  比limit小或者等于
     private int limit;       // 界限  缓冲区中可以操作的容量的大小  limit以外的不能创建  不能大于容量
     private int capacity;    //容量  缓冲区最大可使用的容量 一旦创建不能修改   是最大值

 缓冲区 分类
    默认使用的非直接缓冲区
    当然，也可以使用直接缓冲区(ByteBuffer allocateDir = ByteBuffer.allocateDirect(1024);)。
    此种方式是直接创建到物理内存中,( base = unsafe.allocateMemory(size);),可以提高效率。但是此方式不能被GC回收

 allocateDir.isDirect();//是否是直接缓冲区  true是直接缓冲区


 */
public class TestBuffer {
    //分配大小 1024字节
    ByteBuffer allocate = ByteBuffer.allocate(1024);
    //
    ByteBuffer allocateDir = ByteBuffer.allocateDirect(1024);

    String str="12345";
    @org.junit.Before
    public void before() {
        /**
         -----------------
         位置:0
         限制：1024
         容量：1024
         */
        printByteBufferAttribute(allocate,"初始状态");
        allocateDir.isDirect();//是否是直接缓冲区  true是直接缓冲区
        //存入值   即写入缓冲区
        allocate.put(str.getBytes());
    }

    @Test
    public void ByteBufferDemo(){

        //默认存入了一次str

        /**
         -----------------
         位置:5
         限制：1024
         容量：1024
         */
        printByteBufferAttribute(allocate,null);

        //继续存数据
        allocate.put(str.getBytes());
        /**
         -----------------
         位置:10
         限制：1024
         容量：1024
         */
        printByteBufferAttribute(allocate,null);

        //取值
//        printByteBufferString(allocate);
        printByteBufferStringByFlip(allocate);
        System.out.println("rewind....");
        allocate.rewind();//恢复  可重复读

        /**
         --------rewind后---------
         位置:0
         限制：10
         容量：1024
         */
        printByteBufferAttribute(allocate,"rewind后");

        System.out.println("get rewind str");
        byte[] dst=new byte[allocate.limit()];
        allocate.get(dst);
        System.out.println("内容:"+new String(dst,0,dst.length));
        allocate.clear();//清空缓冲区  但是数据依旧存在   处于被遗忘状态
        /**
         --------clear后---------
         位置:0
         限制：1024
         容量：1024
         */
        printByteBufferAttribute(allocate,"clear后");

    }


    /**
     *标记和恢复 以及剩余多少
     */
    @Test
    public void BFMarkAndReset(){
        allocate.flip();

        byte[] dst=new byte[allocate.limit()];
        allocate.get(dst,0,2);
        printByteBufferAttribute(allocate,"只取两位");
        System.out.println("取值："+new String(dst,0,2));

        //标记以下
        allocate.mark();

        allocate.get(dst,2,2);
        printByteBufferAttribute(allocate,"mark后的第二次取两位");
        System.out.println("取值："+new String(dst,2,2));

        allocate.reset();

        printByteBufferAttribute(allocate,"reset后的");

        //缓冲区中还有
        if (allocate.hasRemaining()) {
            System.out.println("剩余数量："+allocate.remaining());
        }

    }

    /**
     * 打印缓冲区相关属性
     * @param allocate
     * @param text
     */
    private void printByteBufferAttribute(ByteBuffer allocate,String text){
        if (StringUtils.isBlank(text)) {
            text="put方法";
        }
        System.out.println("--------"+text+"---------");
        System.out.println("位置:"+allocate.position());
        System.out.println("限制："+allocate.limit());
        System.out.println("容量："+allocate.capacity());
    }

    /**
     * flip之后的
     * @param allocate
     */
    private void printByteBufferStringByFlip(ByteBuffer allocate){
        //读取数据
        allocate.flip();
        printByteBufferAttribute(allocate,"flip方法后");
        System.out.println("-------flip----------");
        byte[] dst=new byte[allocate.limit()];
        allocate.get(dst);
        System.out.println("内容:"+new String(dst,0,dst.length));
    }
    /**
     * 没有flip的
     * 不能读取到数据
     * @param allocate
     */
    private void printByteBufferString(ByteBuffer allocate){
        //读取数据
        System.out.println("-----------------"+allocate.position());
        byte[] dst=new byte[allocate.position()];
        allocate.get(dst);
        System.out.println("内容:"+new String(dst,0,dst.length));
    }
}
